(*****************************************************************************
 * Delphi Plug-in Framework (DPF)
 * Copyright (C) 2006-2007 Tao Yuan
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the
 * License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.                                                               }
 *
 * The Initial Developer of the Original Code is Tao Yuan. Portions created by
 * Tao Yuan are Copyright (C) Tao Yuan (taoy.cn att gmail dott com)
 * All rights reserved.
 *****************************************************************************)
 
unit RDExtensionPointImpl;

interface

uses
//  Dialogs,
  Rcl,
  RDIdentity,
  RDPluginRegistry, RDPluginRegistryImpl, RDModel, RDExceptions,
  RDConsts, RDPathResolver, RDIntegrityCheckReport, RDIntegrityChecker;

type
  TExtensionPointImpl = class;

  TParameterDefinitionImpl = class(TPluginElementImpl, IParameterDefinition)
  private
    subDefinitions : IList;
    superDefinition : TParameterDefinitionImpl;
    modelParamDef : TModelParameterDef;
    extPoint: TExtensionPointImpl;

    procedure checkMultiplicity;
    procedure checkType;
  public
    constructor Create(aExtensionPoint: IExtensionPoint; aSuperDefinition:
        IParameterDefinition; aModel: TModelParameterDef);
    destructor Destroy; override;
  protected
    (**
     * @return custom data for additional customization of some types
     *)
    function getCustomData: String; stdcall;
    (**
     * @return extension point, this definition belongs to
     *)
    function getDeclaringExtensionPoint: IExtensionPoint; stdcall;
    (**
     * @return multiplicity of parameter, that can be defined according
     *         to this definition
     *)
    function getMultiplicity: String; stdcall;
    (**
     * @param id ID of parameter sub-definition to look for
     * @return parameter sub-definition with given ID
     *)
    function getSubDefinition(id: String): IParameterDefinition; stdcall;
    (**
     * Returns collection of all parameter sub-definitions declared
     * in this parameter definition.
     * @return collection of {@link ExtensionPoint.ParameterDefinition}
     *         objects
     *)
    function getSubDefinitions: IIntfCollection; stdcall;
    (**
     * @return parameter definition, of which this one is child or
     *         <code>null</code> if this is top level parameter definition
     *)
    function getSuperDefinition: IParameterDefinition; stdcall;
    (**
     * @return value type of parameter, that can be defined according
     *         to this definition
     *)
    function getType: String; stdcall;

//    function getDeclaringPluginFragment: IPluginFragment;
//    function getDeclaringPluginDescriptor: IPluginDescriptor;
//    function getDocsPath: String;
//    function getDocumentation: IDocumentation;
//    function getId: String;
    function toString: string; override;
  end;

  TExtensionPointImpl = class(TPluginElementImpl, IExtensionPoint)
  private
    connectedExtensions: IStrMap;
    availableExtensions: IStrMap;
    model: TModelExtensionPoint;
    parameterDefinitions: IList;
    bValid : Boolean;
    paramDefsMerged : Boolean;
    descendants : IList;
    flagValidate: Boolean;
    procedure collectDescendants;
    function isExtensionPointAvailable(pluginId, pointId: string): Boolean;
    procedure updateExtensionsLists;
  protected
    destructor Destroy; override;
    function getAvailableExtension(uniqueId: string): IExtension; stdcall;
    function getAvailableExtensions: IIntfCollection; stdcall;
    function getConnectedExtension(uniqueId: String): IExtension; stdcall;
    function getConnectedExtensions: IIntfCollection; stdcall;
    function getDescendants: IIntfCollection; stdcall;
    function getMultiplicity: String; stdcall;
    function getParameterDefinition(id: String): IParameterDefinition; stdcall;
    function getParameterDefinitions: IIntfCollection; stdcall;
    function getParentExtensionPointId: String; stdcall;
    function getParentPluginId: String; stdcall;
    function getUniqueId: String; stdcall;
    function isExtensionAvailable(uniqueId: string): Boolean; stdcall;
    function isExtensionConnected(uniqueId: String): boolean; stdcall;
    function isSuccessorOf(extensionPoint: IExtensionPoint): boolean; stdcall;
    function isValid: Boolean; stdcall;
    function toString: string; stdcall;
    function Validate: IIntfCollection; stdcall;
  public
    constructor Create(descr: IPluginDescriptor; aFragment: IPluginFragment;
        aModel: TModelExtensionPoint);
    procedure registryChanged;
  end;

implementation

uses
  SysUtils;

constructor TParameterDefinitionImpl.Create(aExtensionPoint: IExtensionPoint;
    aSuperDefinition: IParameterDefinition; aModel: TModelParameterDef);
var
  names: IStrSet;
  it: IIterator;
  def: TParameterDefinitionImpl;
begin      
  if aExtensionPoint <> nil then
    extPoint := TExtensionPointImpl(aExtensionPoint.Implementor);

  inherited Create(extPoint.getDeclaringPluginDescriptor,
          extPoint.getDeclaringPluginFragment,
          aModel.Id, aModel.Documentation);
  if aSuperDefinition <> nil then
    superDefinition := TParameterDefinitionImpl(aSuperDefinition.Implementor);
  modelParamDef := aModel;
  checkType();
  checkMultiplicity();
  if Rcl.Str.IsEqual(TYPE_ANY, modelParamDef._type) then
      subDefinitions := TArrayList.Create
  else
  begin
      subDefinitions := TArrayList.Create(
              modelParamDef.ParamDefs.size);
      names := TStrHashSet.Create;
      it := modelParamDef.ParamDefs.First;
      while it.HasNext do
      begin
        def := TParameterDefinitionImpl.Create(extPoint, Self, TModelParameterDef(it.Next));
        if names.Contains(def.getId) then
          raise EManifestProcessing.Create(
            'dpf.plugin.registry.xml',
            'duplicateParameterDefinition',
            [def.getId, extPoint.getId, extPoint.getDeclaringPluginDescriptor.getId]
            );
        names.Add(def.getId);
        (subDefinitions as IIntfCollection).Add(def);
      end;  
      subDefinitions := Collections.unmodifiableList(subDefinitions);
  end;
  log.debug('object instantiated: ' + Self.toString); //$NON-NLS-1$
end;

destructor TParameterDefinitionImpl.Destroy;
begin
  inherited;
  // TODO -cMM: TParameterDefinitionImpl.Destroy default body inserted
end;

procedure TParameterDefinitionImpl.checkMultiplicity;
var
  multiplicity: string;
begin
  multiplicity := modelParamDef.multiplicity;
  if (not Rcl.Str.IsEqual(MULT_ONE, multiplicity))
          and (not Rcl.Str.IsEqual(MULT_ANY, multiplicity))
          and (not Rcl.Str.IsEqual(MULT_NONE_OR_ONE, multiplicity))
          and (not Rcl.Str.IsEqual(MULT_ONE_OR_MORE, multiplicity)) then
  begin
    raise EManifestProcessing.Create(
            'dpf.plugin.registry.xml', //$NON-NLS-1$
            'invalidMultiplicityAttribute', //$NON-NLS-1$
            [multiplicity, extPoint.getId(),
                extPoint.getDeclaringPluginDescriptor.getId]);
  end;
end;

procedure TParameterDefinitionImpl.checkType;
var
  sType: string;
begin
  sType := modelParamDef._type;
  if ((not Rcl.Str.IsEqual(TYPE_STRING, sType))
          and (not Rcl.Str.EndsWith(sType, TYPE_BOOLEAN))
          and (not Rcl.Str.IsEqual(TYPE_NUMBER, sType))
          and (not Rcl.Str.IsEqual(TYPE_DATE, sType))
          and (not Rcl.Str.IsEqual(TYPE_TIME, sType))
          and (not Rcl.Str.IsEqual(TYPE_DATETIME, sType))
          and (not Rcl.Str.IsEqual(TYPE_NULL, sType))
          and (not Rcl.Str.IsEqual(TYPE_ANY, sType))
          and (not Rcl.Str.IsEqual(TYPE_PLUGIN_ID, sType))
          and (not Rcl.Str.IsEqual(TYPE_EXTENSION_POINT_ID, sType))
          and (not Rcl.Str.IsEqual(TYPE_EXTENSION_ID, sType))
          and (not Rcl.Str.IsEqual(TYPE_FIXED, sType))
          and (not Rcl.Str.IsEqual(TYPE_RESOURCE, sType))) then
  begin
      raise EManifestProcessing.Create(
              'dpf.plugin.registry.xml', //$NON-NLS-1$
              'invalidTypeAttribute', //$NON-NLS-1$
              [sType, extPoint.getId,
                  extPoint.getDeclaringPluginDescriptor.getId]);
  end;
end;

function TParameterDefinitionImpl.getCustomData: String;
begin
   Result := modelParamDef.customData;
end;

function TParameterDefinitionImpl.getDeclaringExtensionPoint: IExtensionPoint;
begin
   Result := extPoint as IExtensionPoint;
end;

function TParameterDefinitionImpl.getMultiplicity: String;
begin
   Result := modelParamDef.multiplicity;
end;

function TParameterDefinitionImpl.getSubDefinition(id: String):
    IParameterDefinition;
var
  it: IIterator;
  def: IParameterDefinition;
begin
  it := subDefinitions.First;
  while it.HasNext do
  begin
    Supports(it.Next, IParameterDefinition, def);
//    def := it.Next as IParameterDefinition;
    if Rcl.Str.IsEqual(def.getId, id) then
    begin
      Result := def;
      Exit;
    end;
  end;

  raise EIllegalArgument.Create('parameter definition with ID ' + id
    + ' not found in extension point ' + extPoint.getUniqueId);

end;

function TParameterDefinitionImpl.getSubDefinitions: IIntfCollection;
begin
   Result := Collections.ToIntfCollection(subDefinitions);
end;

function TParameterDefinitionImpl.getSuperDefinition: IParameterDefinition;
begin
   Result := superDefinition;
end;

function TParameterDefinitionImpl.getType: String;
begin
  Result := modelParamDef._type;
end;

function TParameterDefinitionImpl.toString: string;
begin
  Result := '{PluginExtensionPoint.ParameterDefinition: extPointUid=' //$NON-NLS-1$
                + getDeclaringExtensionPoint.getUniqueId + '; id=' + getId //$NON-NLS-1$
                + '}'; //$NON-NLS-1$;
end;

constructor TExtensionPointImpl.Create(descr: IPluginDescriptor; aFragment:
    IPluginFragment; aModel: TModelExtensionPoint);
var
  names: IStrCollection;
  it: IIterator;
  def: TParameterDefinitionImpl;
begin
  inherited Create(descr, aFragment, aModel.id, aModel.Documentation);
  model := aModel;
  if (model.ParentPointId <> '')
          and (model.ParentPluginId = '') then
  begin
      log.warn('ExtensionPoint plug-in ID not specified together with prent' //$NON-NLS-1$
              + ' extension point ID, using declaring plug-in ID,' //$NON-NLS-1$
              + ' extension point is ' + getUniqueId()); //$NON-NLS-1$
      model.ParentPluginId := descr.getId;
  end;
  parameterDefinitions := TArrayList.Create(model.ParamDefs.size);
  names := TStrHashSet.Create;
  it := model.ParamDefs.First;
  while it.HasNext do
  begin
    def := TParameterDefinitionImpl.Create(Self, nil, TModelParameterDef(it.Next));
    if names.Contains(def.getId) then
      raise EManifestProcessing.Create('dpf.plugin.registry.xml',
        'duplicateParameterDefinition',
        [def.getId, getId, descr.getId]);
    names.Add(def.getId);
    parameterDefinitions.Add(def);
  end;

//  parameterDefinitions =
//      Collections.unmodifiableList(parameterDefinitions);
  log.debug('object instantiated: ' + Self.toString); //$NON-NLS-1$

end;

destructor TExtensionPointImpl.Destroy;
begin
//  connectedExtensions := nil;
  inherited;
end;

procedure TExtensionPointImpl.collectDescendants;
var
  it, it2: IIntfIterator;
  descr: IPluginDescriptor;
  extp: IExtensionPoint;
//  extpObj: TObject;
begin
  descendants := TLinkedList.Create;
  it := getDeclaringPluginDescriptor.getRegistry.getPluginDescriptors
          .First;
  while it.HasNext do
  begin
    Supports(it.Next, IPluginDescriptor, descr);
//    descr := IPluginDescriptor(it.Next);
    it2 := descr.getExtensionPoints.First;
    while it2.HasNext do
    begin
//      extpObj := it2.Next;
      Supports(it2.Next, IExtensionPoint, extp);
//      extp := IExtensionPoint(it2.Next);
      if extp.isSuccessorOf(Self) then
      begin
        log.Debug('extension point ' + extp.getUniqueId //$NON-NLS-1$
                      + ' is descendant of point ' + Self.getUniqueId);
        descendants.Add(extp.Implementor);
      end;
    end;  
  end;          
  descendants := Collections.unmodifiableList(descendants);
end;

function TExtensionPointImpl.getAvailableExtension(
  uniqueId: string): IExtension;
begin
  if (availableExtensions = nil) then
      updateExtensionsLists();

  if not Supports(availableExtensions.Items[uniqueId], IExtension, Result) then
      EIllegalArgument.Create('extension ' + uniqueId //$NON-NLS-1$
          + ' not available in point ' + getUniqueId()); //$NON-NLS-1$
end;

function TExtensionPointImpl.getAvailableExtensions: IIntfCollection;
begin
  if (availableExtensions = nil) then
      updateExtensionsLists();

  Result := Collections.unmodifiableCollection(
      Collections.ToIntfCollection(availableExtensions.values));
end;

function TExtensionPointImpl.getConnectedExtension(
  uniqueId: String): IExtension;
begin
  if (connectedExtensions = nil) then updateExtensionsLists;

  Supports(connectedExtensions.GetValue(uniqueId),
      IExtension, Result);
//  Result := IExtension(connectedExtensions.GetValue(uniqueId));
  if (result = nil) then
    raise EIllegalArgument.Create('extension ' + uniqueId //$NON-NLS-1$
        + ' not connected to point ' + getUniqueId()); //$NON-NLS-1$
end;

function TExtensionPointImpl.getConnectedExtensions: IIntfCollection;
begin
  if (connectedExtensions = nil) then updateExtensionsLists;
 //  Result := Collections.unmodifiableCollection(connectedExtensions.values());
   Result := Collections.ToIntfCollection(connectedExtensions.values);
end;

function TExtensionPointImpl.getDescendants: IIntfCollection;
begin
  if (descendants = nil) then
      collectDescendants;
  Result := Collections.ToIntfCollection(descendants);
end;

function TExtensionPointImpl.getMultiplicity: String;
begin
  Result := model.ExtensionMultiplicity;
end;

{ TExtensionPointImpl }

function TExtensionPointImpl.getParameterDefinition(
  id: String): IParameterDefinition;
var
  it: IIntfIterator;
  def: IParameterDefinition;
begin
  it := getParameterDefinitions.First;
  while it.HasNext do
  begin
    Supports(it.Next, IParameterDefinition, def);
//    def := IParameterDefinition(it.Next);
    if Rcl.Str.IsEqual(def.getId, id) then
    begin
      Result := def;
      Exit;
    end;
  end;

  raise EIllegalArgument.Create('parameter definition with ID ' + id //$NON-NLS-1$
      + ' not found in extension point ' + getUniqueId //$NON-NLS-1$
      + ' and all it parents');
end;

function TExtensionPointImpl.getParameterDefinitions: IIntfCollection;
var
  names: IStrSet;
  parentParamDefs: IIntfCollection;
  newParamDefs: IList;
  it: IIterator;
  it1: IIntfIterator;
  def: IParameterDefinition;
//  defObj: TObject;
begin
  if ((model.ParentPluginId = '')
          or (model.ParentPointId = '') or paramDefsMerged) then
  begin
    Result := Collections.ToIntfCollection(parameterDefinitions);
    Exit;
  end;
  
  names := TStrHashSet.Create;
  parentParamDefs :=
      getDeclaringPluginDescriptor.getRegistry.getExtensionPoint(
              model.ParentPluginId, model.ParentPointId)
              .getParameterDefinitions;
  newParamDefs := TArrayList.Create(parameterDefinitions.Size
          + parentParamDefs.size);

  it := parameterDefinitions.First;
  while it.HasNext do
  begin
//    defObj := it.Next;
    Supports(it.Next, IParameterDefinition, def);
//    def := IParameterDefinition(it.Next);
    names.Add(def.getId);
    newParamDefs.Add(def.Implementor);
  end;

  it1 := parentParamDefs.First;
  while it1.HasNext do
  begin
//    defObj := it1.Next;
    Supports(it1.Next, IParameterDefinition, def);
//    def := IParameterDefinition(it.Next);
    if names.Contains(def.getId) then Continue;
    newParamDefs.Add(def.Implementor);
  end;

  paramDefsMerged := true;
  parameterDefinitions := Collections.unmodifiableList(newParamDefs);
  Result := Collections.ToIntfCollection(parameterDefinitions);
end;

function TExtensionPointImpl.getParentExtensionPointId: String;
begin
  Result := model.ParentPointId;
end;

function TExtensionPointImpl.getParentPluginId: String;
begin
  Result := model.ParentPluginId;
end;

function TExtensionPointImpl.getUniqueId: String;
begin
  Result := getDeclaringPluginDescriptor.getRegistry.makeUniqueId(
                getDeclaringPluginDescriptor.getId, getId);
end;

function TExtensionPointImpl.isExtensionAvailable(uniqueId: string): Boolean;
begin
  if (availableExtensions = nil) then
      updateExtensionsLists();

  Result := availableExtensions.ContainsKey(uniqueId);
end;

function TExtensionPointImpl.isExtensionConnected(uniqueId: String): boolean;
begin
  if (connectedExtensions = nil) then updateExtensionsLists();
  Result := connectedExtensions.containsKey(uniqueId);
end;

function TExtensionPointImpl.isExtensionPointAvailable(pluginId, pointId:
    string): Boolean;
var
  registry: IPluginRegistry;
  it: IIntfIterator;
  extPoint: IExtensionPoint;
begin
  registry := getDeclaringPluginDescriptor().getRegistry();
  if (not registry.isPluginDescriptorAvailable(pluginId)) then
      Exit; //return false;

  it := registry.getPluginDescriptor(pluginId).getExtensionPoints.First;
  while it.HasNext do
  begin
    if Supports(it.Next, IExtensionPoint, extPoint) then
      if Rcl.Str.IsEqual(extPoint.getId, pointId) then
      begin
        Result := True;
        Exit;
      end;
  end;
end;

function TExtensionPointImpl.isSuccessorOf(
  extensionPoint: IExtensionPoint): boolean;
begin
  if ((model.ParentPluginId = '')
          or (model.ParentPointId = '')) then
  begin
    Result := false;
    Exit;
  end;
  
  if Rcl.Str.IsEqual(model.ParentPluginId,
          extensionPoint.getDeclaringPluginDescriptor.getId)
          and Rcl.Str.IsEqual(model.ParentPointId, extensionPoint.getId) then
  begin
   Result := true;
   Exit;
  end;
  try
    Result := getDeclaringPluginDescriptor.getRegistry
        .getExtensionPoint(model.ParentPluginId,
                model.ParentPointId).isSuccessorOf(extensionPoint);
  except
    on eia: EIllegalArgument do
      Result := False;
  end;
end;

function TExtensionPointImpl.isValid: boolean;
begin
  if (not flagValidate) then
    validate();
  Result := bValid;
end;

procedure TExtensionPointImpl.registryChanged;
begin
  flagValidate := False;;
  connectedExtensions := nil;
  availableExtensions := nil;
  descendants := nil;
end;

function TExtensionPointImpl.toString: string;
begin
  Result := '{ExtensionPoint: uid=' + getUniqueId + '}';
end;

procedure TExtensionPointImpl.updateExtensionsLists;
var
  it, it2: IIntfIterator;
  descr: IPluginDescriptor;
//  descrObj: TObject;
  ext: IExtension;
//  extObj: TObject;
begin
  connectedExtensions := TStrHashMap.Create(16, False);
  availableExtensions := TStrHashMap.Create(16, False);

  it := getDeclaringPluginDescriptor.getRegistry.getPluginDescriptors.First;
  while it.HasNext do
  begin
//    descrObj := it.Next;
    Supports(it.Next, IPluginDescriptor, descr);
//    descr := IPluginDescriptor(it.Next);
    it2 := descr.getExtensions.First;
    while it2.HasNext do
    begin
//      extObj := it2.Next;
      Supports(it2.Next, IExtension, ext);

//      ShowMessage(getDeclaringPluginDescriptor.getId + ' = ' +
//        ext.getExtendedPluginId + '? and ' +
//        getId + ' = ' +
//        ext.getExtendedPointId + '?');

      if Rcl.Str.IsEqual(getDeclaringPluginDescriptor.getId,
                        ext.getExtendedPluginId) and
        Rcl.Str.IsEqual(getId, ext.getExtendedPointId) then
      begin
        availableExtensions.PutValue(ext.getUniqueId, ext.Implementor);

        if ext.isValid then
        begin
          log.Debug('extension ' + ext.getExtendedPluginId //$NON-NLS-1$
                          + ' connected to point ' + getUniqueId);
          connectedExtensions.PutValue(ext.getUniqueId, ext.Implementor);
        end
        else
          log.Warn('extension ' + ext.getUniqueId() //$NON-NLS-1$
                          + ' is invalid and doesn''t connected to' //$NON-NLS-1$
                          + ' extension point ' + getUniqueId());
      end;
    end;
  end;
end;

function TExtensionPointImpl.Validate: IIntfCollection;
var
  foundPlugins: IStrSet;
  it: IIntfIterator;
  pluginId: string;
  ext: IExtension;
begin
  flagValidate := True;
  if ((model.ParentPluginId <> '') and (model.ParentPointId <> '')) then
  try
    if (not isExtensionPointAvailable(model.ParentPluginId,
            model.ParentPointId)) then
    begin
        bValid := FALSE;
        Result := Collections.singletonList(TReportItemImpl.Create(SEVERITY_ERROR,
                      Self, ERROR_INVALID_EXTENSION_POINT,
                      'parentExtPointNotAvailable', [
                      getDeclaringPluginDescriptor.getRegistry
                                .makeUniqueId(model.ParentPluginId,
                                        model.ParentPointId), getUniqueId]) as IInterface);
        Exit;
    end;
  except
    on e: Exception do
    begin
      bValid := FALSE;
      log.debug('failed checking availability of extension point ' //$NON-NLS-1$
              + getDeclaringPluginDescriptor().getRegistry()
                  .makeUniqueId(model.ParentPluginId,
                          model.ParentPointId));
      Result := Collections.singletonList(
              TReportItemImpl.Create(
              SEVERITY_ERROR, Self,
              ERROR_INVALID_EXTENSION_POINT,
              'ExtPointAvailabilityCheckFailed', [  //$NON-NLS-1$
              getDeclaringPluginDescriptor.getRegistry
                  .makeUniqueId(model.ParentPluginId,
                          model.ParentPointId),
              getUniqueId, e.Message])  as IInterface);
       Exit;
     end;
  end;

  if Rcl.Str.IsEqual(EXT_MULT_ANY, getMultiplicity) then
  begin
      bValid := TRUE;
      Result := nil;//Collections.EMPTY_LIST;
      Exit;
  end else if Rcl.Str.IsEqual(EXT_MULT_ONE,getMultiplicity) then
  begin
      bValid := getAvailableExtensions.size = 1;
      if not bValid then
      begin
          Result := Collections.singletonList(
                  TReportItemImpl.Create(
                  SEVERITY_ERROR, Self,
                  ERROR_INVALID_EXTENSION_POINT,
                  'toManyOrFewExtsConnected', [getUniqueId])  as IInterface); //$NON-NLS-1$
          Exit;
      end;
  end else if Rcl.Str.IsEqual(EXT_MULT_NONE, getMultiplicity) then
  begin
    bValid := getAvailableExtensions.size = 0;
    if (not bValid) then
    begin
        Result := Collections.singletonList(
                TReportItemImpl.Create(
                SEVERITY_ERROR, Self,
                ERROR_INVALID_EXTENSION_POINT,
                'extsConnectedToAbstractExtPoint', [getUniqueId]) as IInterface); //$NON-NLS-1$
        Exit;
    end
  end else begin
      // MULT_ONE_PER_PLUGIN case
      bValid := TRUE;
      foundPlugins := TStrHashSet.Create;
      it := getAvailableExtensions.First;
      while it.HasNext do
      begin
        Supports(it.Next, IExtension, ext);
        pluginId := ext.getDeclaringPluginDescriptor.getId;
        if not foundPlugins.Add(pluginId) then
        begin
          bValid := False;
          Result := Collections.singletonList(
                      TReportItemImpl.Create(
                      SEVERITY_ERROR, Self,
                      ERROR_INVALID_EXTENSION_POINT,
                      'toManyExtsConnected', [getUniqueId]) as IInterface); //$NON-NLS-1$;
          Exit;
        end;
      end;

  end;
  Result := nil;// Collections.EMPTY_LIST;
end;



end.
